#include "graphics/utils.h"
#include "ray_marching_demo.h"

namespace venus {
bool RayMarchingDemo::Initialize() {
  glewInit();
  if (!glewIsSupported( "GL_VERSION_2_0 GL_EXT_framebuffer_object")) {
    printf( "Required extensions not supported.\n");
    return false;
  }
  glEnable(GL_DEPTH_TEST);
  cg_context_ = cgCreateContext();
  fluid_system_ = new FluidSystem(cg_context_, 128, 128, 128);
  fluid_system_->Splat();
  volume_renderer = new VolumeRenderer(cg_context_, 
                                       fluid_system_->GetStateBuffer());
  volume_renderer->set_density(0.5);
  volume_renderer->set_brightness(1.0);
  options_[OPTION_DRAW_CUBE] = true;
  options_[OPTION_SIMULATE] = true;
  options_[OPTION_AUTO_SEED] = true;
  return true;
}

void RayMarchingDemo::OnDisplay() {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  camera_.ApplyViewTransform();

  // run simulation
  if (options_[OPTION_SIMULATE]) {
    if ( options_[OPTION_AUTO_SEED] && ((rand() & 0xff) > 220)) {
       fluid_system_->Splat();
    }
    fluid_system_->GetStateBuffer()->SetFiltering(GL_NEAREST);
    fluid_system_->Step(1.0f);
  }
  // render volume
  glViewport(0, 0, this->width(), this->height());
  fluid_system_->GetStateBuffer()->SetFiltering(GL_LINEAR);
  volume_renderer->set_volume(fluid_system_->GetStateBuffer());
  volume_renderer->Render();

  if (options_[OPTION_DRAW_CUBE]) glutWireCube(2.0f);
  DisplayStastics("frame rate", fps_counter_.Update(), "fps");
  glutSwapBuffers();
}

void RayMarchingDemo::OnResize(int width, int height) {
  this->set_width(width);
  this->set_height(height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  camera_.set_aspect_ratio(static_cast<double>(width)/height);
  camera_.ApplyProjectionTransform(); 
  glViewport(0, 0, width, height);
}
void RayMarchingDemo::OnIdle() {
  this->ReDraw();
}
void RayMarchingDemo::OnKeyboard(unsigned char key, int x, int y) {
  switch (key) {
    case 'a':
      camera_.Yaw(-1);
      break;
    case 'd':
      camera_.Yaw(1);
      break;
    case 'w':
      camera_.Walk(1);
      break;
    case 's':
      camera_.Walk(-1);
      break;
    case 'q':
      camera_.Pitch(1);
      break;
    case 'z':
      camera_.Pitch(-1);
      break;
  }
}

} // namespace venus
